
#include "mutex.h"
#include  "../image.h"
#include "../ImageFratory.h"
#include <complex>
#include <vector>
#include <iostream>
#ifndef JULIA_H
#define JULIA_H
using std::vector;
using std::cout;
struct Julia_Set_Info{
    std::complex<double> c;
    int width;
    int height;
    double x_scale;
    double y_scale;
};
bool compare(vector<Block<4> >::iterator F,vector<Block<4> >::iterator L,Block<4> const & val)
{
    for(;F!=L;++F){
        if(compare<4>(*F,val)<30) return false;
    }
    return true;
}
struct JuliaThread{
    int thread_id;
    Julia_Set_Info parame;
    JuliaThread(Julia_Set_Info const & info,int id):parame(info),thread_id(id){}
    void operator()(){
        Mutex::cout_mutex.lock();
        cout<<"Thread "<<thread_id<<" is running\n";
        Mutex::cout_mutex.unlock();
        Image *p=CreateJuliaSet();
        int add_block_number=0;
        for(int scale=2;scale<=255;++scale){
            Image *pImage=ScaleImage(p,scale);
            vector<Block<4> > blocks=SplitBlock(pImage);
            Mutex::cout_mutex.lock();
            Mutex::cout_mutex.unlock();
            for(vector<Block<4> >::iterator it=blocks.begin();it!=blocks.end();++it){
                for(int i=0;i<8;i++){
                    Block<4> transform_block=it->Transform(i);
                    int btc_code=transform_block.BTC().to_uint();
                    Mutex::dictionary_mutex.lock();
                    if(dictionary_block_number[btc_code]<100){
                        if(compare(dictionary[btc_code].begin(),dictionary[btc_code].begin()+dictionary_block_number[btc_code],transform_block)){
                            dictionary[btc_code][dictionary_block_number[btc_code]]=transform_block;
                            dictionary_block_number[btc_code]+=1;
                            add_block_number++;
                        }
                    }
                    Mutex::dictionary_mutex.unlock();
                }
            }
            delete pImage;
        }
        delete p;
        Mutex::thread_count_mutex.lock();
        Global::thread_count-=1;
        Mutex::thread_count_mutex.unlock();
        Mutex::cout_mutex.lock();
        cout<<"Thread "<<thread_id<<" is exit and add "<<add_block_number<<"\n";
        Mutex::cout_mutex.unlock();
        Mutex::thread_created_condition.notify_one();
    }
private:
    Image * CreateJuliaSet(){
        Image *p=new Image(parame.width,parame.height);
        double x_left=0-(parame.width-1)/2*parame.x_scale;
        double y_top=0+(parame.height-1)/2*parame.y_scale;
        for(int i=0;i<parame.height;++i){
            for(int j=0;j<parame.width;++j){
                int k=0;
                std::complex<double> z(x_left+j*parame.x_scale,y_top-i*parame.y_scale);
                while(k++<20  && std::abs(z)<100){
                    z=z*z+parame.c;
                }
                p->SetValue(i,j,k);
            }
        }
        return p;
    }
    Image *ScaleImage(Image *p,int scale){
        Image *pret=new Image(p->GetWidth(),p->GetHeight());
        for(int i=0;i<p->GetHeight();++i){
            for(int j=0;j<p->GetWidth();++j){
                pret->SetValue(i,j,(p->GetValue(i,j)*scale)%256);
            }
        }
        return pret;
    }
    vector<Block<4> > SplitBlock(Image *p)
    {
        vector<Block<4> > ret;
        for(int i=0;i<parame.height;i+=8){
            for(int j=0;j<parame.width;j+=8){
                Block<4> block;
                for(int k=0;k<4;++k){
                    for(int l=0;l<4;++l){
                        block[k][l]=(p->GetValue(i+2*k,2*l+j)+p->GetValue(i+2*k+1,2*l+j)+p->GetValue(i+2*k,2*l+j+1)+p->GetValue(i+2*k+1,2*l+j+1))/4;
                    }
                }
                ret.push_back(block);
            }
        }
        return ret;
    }
};
#endif
